package com.leyou.order.service;

import com.fasterxml.jackson.databind.type.CollectionLikeType;
import com.leyou.common.constants.UserHolder;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.upload.Path;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.dto.SkuDTO;
import com.leyou.item.client.ItemClient;
import com.leyou.order.dto.*;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderDetail;
import com.leyou.order.pojo.OrderLogistics;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.UserClient;
import com.leyou.user.domain.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
@Transactional
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private IdWorker idWorker;

    //创建订单逻辑
    public Long saveOrder(CartToOrderDTO cartToOrderDTO) {
        try {
            //收货人地址id
            Long addressId = cartToOrderDTO.getAddressId();
            //购物车对象集合  购物车对象里面两个字段 skuid 数量
            List<CartDTO> carts = cartToOrderDTO.getCarts();
            //支付类型
            Integer paymentType = cartToOrderDTO.getPaymentType();
            //添加数据到订单表
            Order order = new Order();
            //发票类型 0无发票1普通发票，2电子发票，3增值税发票
            order.setInvoiceType(0);
            order.setOrderId(idWorker.nextId());
            order.setPaymentType(paymentType);
            order.setUserId(UserHolder.getUserId());
            //优惠id
            order.setPromotionIds(null);
            //订单来原 1:app端，2：pc端，3：微信端',
            order.setSourceType(2);
            //订单的状态，1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货，交易成功 5、交易取消，订单关闭 6、交易结束，已评价',
            order.setStatus(1);
            //真实付款金额
            order.setActualFee(1L);
            //邮费
            order.setPostFee(0L);
            //skuids 集合
            List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
            //把 carts变成一个map
            Map<Long, Integer> cartMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
            //通过skuid得到 sku对象
            List<SkuDTO> skus = itemClient.findSkusBySkuIds(skuIds);
            //遍历得到总价格  map 收集到的是 object 类型
            long sum = skus.stream().mapToLong(skuDTO -> skuDTO.getPrice() * cartMap.get(skuDTO.getId())).sum();
            //总价格
            order.setTotalFee(sum);
            orderMapper.insertSelective(order);
            //创建一个orderDetail对象集合 用于存储订单详情
            List<OrderDetail> list = new ArrayList<>();
            //添加数据到订单详情表
            skus.forEach(sku ->{
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setId(idWorker.nextId());
                orderDetail.setImage(StringUtils.substringBefore(sku.getImages(),","));
                orderDetail.setNum(cartMap.get(sku.getId()));
                orderDetail.setOrderId(order.getOrderId());
                orderDetail.setOwnSpec(sku.getOwnSpec());
                orderDetail.setPrice(sku.getPrice());
                orderDetail.setSkuId(sku.getId());
                orderDetail.setTitle(sku.getTitle());
                list.add(orderDetail);
            });
            orderDetailMapper.insertList(list);
            //添加订单数据到物流表
            AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUserId(), addressId);
            //将当前用户的地址信息转换成物流信息
            OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
            orderLogistics.setLogisticsCompany("菜鸟");
            orderLogistics.setLogisticsNumber(String.valueOf(idWorker.nextId()));
            orderLogistics.setOrderId(order.getOrderId());
            orderLogisticsMapper.insertSelective(orderLogistics);
            //减库存
            itemClient.minusStock(cartMap);
            return order.getOrderId();
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

    }

    //查询订单详情 id是订单的id
    public OrderDTO findOrderById(Long id) {
        Order order = orderMapper.selectByPrimaryKey(id);
        if(order == null){
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        OrderDTO orderDTO = BeanHelper.copyProperties(order, OrderDTO.class);

        //查询物流信息
        OrderLogistics orderLogistics = orderLogisticsMapper.selectByPrimaryKey(id);
        if(orderLogistics == null){
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        OrderLogisticsDTO orderLogisticsDTO = BeanHelper.copyProperties(orderLogistics, OrderLogisticsDTO.class);
        orderDTO.setLogistics(orderLogisticsDTO);

        //查询订单详情信息
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(id);
        List<OrderDetail> orderDetails = orderDetailMapper.select(orderDetail);
        if(CollectionUtils.isEmpty(orderDetails)){
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        orderDTO.setDetailList(BeanHelper.copyWithCollection(orderDetails, OrderDetailDTO.class));

        return orderDTO;
    }

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayHelper payHelper;

    //获取二维码的业务方法 id是订单的编号
    public String getPayUrl(Long id) {
        //先判断订单是否存在于 redis中
        String payKey = Path.ORDER_PAY_RUL_PRE + id;
        if(redisTemplate.hasKey(payKey)){
            //存在就返回 二维码url
            //这里是为了防止 用户一直刷新页面 支付 所以用到redis
            log.info("【统一下单】业务成功！");
            return redisTemplate.opsForValue().get(payKey);
        }
        //不存在
        //查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        if(order == null){
            //订单不存在
            log.info("【统一下单】业务失败！订单不存在");
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        //这里的判断是为了防止用户 直接通过 url 访问 服务器而输入了数据库中已存在已经支付的订单号
        //也有可能是自己的订单已经付款了 由于网络原因又点击了
        if(order.getStatus()!= 1){
            log.info("【统一下单】业务失败！订单已支付");
            throw new LyException(502,"订单已支付");
        }
        //订单存在 数据库 且不存在缓存库 存入 缓存库
        //设置时间为2小时
        String payUrl = payHelper.getPayUrl(id, order.getActualFee());
        redisTemplate.opsForValue().set(payKey, payUrl,2, TimeUnit.HOURS);
        return payUrl;
    }

    //这个方法是为了检测 用户是否支付
    public Integer getPayState(Long id) {
        //查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        if(order == null){
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        return order.getStatus();
    }

    //微信回调 业务检测 支付金额是否正确
    public void wxNotify(Map<String, String> maps) {
        //一样需要验证 用心标只，业务标志
        payHelper.checkReturnAndResultCode(maps);
        //获取订单号
        Long wxOrderId = Long.valueOf(maps.get("out_trade_no"));
        //获取金额
        Long totalFee = Long.valueOf(maps.get("total_fee"));
        Order order = orderMapper.selectByPrimaryKey(wxOrderId);
        if(order == null){
            throw new LyException(501,"【微信通知】异常 订单不存在");
        }
        //验证金额
        if(!totalFee.equals(order.getActualFee())){
            throw new LyException(501,"【微信通知】异常 金额不对");
        }
        if(order.getStatus()!=1){
            log.info("【微信通知】订单已支付");
        }
        //更新订单状态
        Order record = new Order();
        record.setOrderId(wxOrderId);
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        int count = orderMapper.updateByPrimaryKeySelective(record);
        if(count!=1){
            //应该将异常订单入库，在后台手动处理。
            log.info("【微信通知】修改订单状态异常！");
        }
    }
}
